package configs

import (
	"dashenwo.com/dashenwo/micro_srv/user_srv/internal/model"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
	"github.com/micro/go-micro/v2/util/log"
	"sync"
	"time"
)

var (
	Db   *gorm.DB
	Once sync.Once
	Err  error
)

// 初始化数据库
func InitDB() {
	Once.Do(func() {
		sqlConnection := DbConf.User + ":" + DbConf.Password + "@tcp(" + DbConf.Host + ":" + DbConf.Port + ")/" + DbConf.Name + "?charset=utf8mb4&parseTime=True&loc=Local"
		Db, Err = gorm.Open(DbConf.Engine, sqlConnection)
		if Err != nil {
			log.Fatal(Err)
		}
		Db.DB().SetMaxOpenConns(DbConf.MaxOpenConns)
		Db.DB().SetMaxIdleConns(DbConf.MaxIdleConns)
		Db.DB().SetConnMaxLifetime(DbConf.ConnMaxLifetime)
		Db.SingularTable(true)
		Db.LogMode(true)
		gorm.DefaultTableNameHandler = getTableName
		Db.Callback().Create().Replace("gorm:update_time_stamp", updateTimeStampForCreateCallback)
		Db.Callback().Update().Replace("gorm:update_time_stamp", updateTimeStampForUpdateCallback)
		Db.Callback().Delete().Replace("gorm:delete", deleteCallback)
		// 创建数据库
		Err = Db.AutoMigrate(&model.User{}).Error
		if Err != nil {
			log.Fatal(Err)
		}
		// TODO 数据初始化
	})
}

// 获取数据库连接
func GetDb() *gorm.DB {
	return Db
}

// 获取带前缀的表名
func getTableName(db *gorm.DB, defaultTableName string) string {
	return "dsw_" + defaultTableName
}

// // 注册新建钩子在持久化之前
func updateTimeStampForCreateCallback(scope *gorm.Scope) {
	if !scope.HasError() {
		nowTime := time.Now().Unix()
		if createTimeField, ok := scope.FieldByName("CreatedTime"); ok {
			if createTimeField.IsBlank {
				_ = createTimeField.Set(nowTime)
			}
		}

		if modifyTimeField, ok := scope.FieldByName("UpdatedTime"); ok {
			if modifyTimeField.IsBlank {
				_ = modifyTimeField.Set(nowTime)
			}
		}
	}
}

// 注册更新钩子在持久化之前
func updateTimeStampForUpdateCallback(scope *gorm.Scope) {
	if _, ok := scope.Get("gorm:update_column"); !ok {
		_ = scope.SetColumn("UpdatedTime", time.Now().Unix())
	}
}

// 注册删除钩子在删除之前
func deleteCallback(scope *gorm.Scope) {
	if !scope.HasError() {
		var extraOption string
		if str, ok := scope.Get("gorm:delete_option"); ok {
			extraOption = fmt.Sprint(str)
		}

		deletedOnField, hasDeletedOnField := scope.FieldByName("DeletedTime")

		if !scope.Search.Unscoped && hasDeletedOnField {
			scope.Raw(fmt.Sprintf(
				"UPDATE %v SET %v=%v%v%v",
				scope.QuotedTableName(),
				scope.Quote(deletedOnField.DBName),
				scope.AddToVars(time.Now().Unix()),
				addExtraSpaceIfExist(scope.CombinedConditionSql()),
				addExtraSpaceIfExist(extraOption),
			)).Exec()
		} else {
			scope.Raw(fmt.Sprintf(
				"DELETE FROM %v%v%v",
				scope.QuotedTableName(),
				addExtraSpaceIfExist(scope.CombinedConditionSql()),
				addExtraSpaceIfExist(extraOption),
			)).Exec()
		}
	}
}
func addExtraSpaceIfExist(str string) string {
	if str != "" {
		return " " + str
	}
	return ""
}
